/**
 * 
 */
package instant.mail;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import javax.mail.internet.InternetAddress;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.speech.RecognizerIntent;
import android.text.ClipboardManager;
import android.text.TextUtils;

/**
 * @author qiangli
 * 
 */
public final class Utils {

	private static final String[] DATA_PATH_PROJECTION = new String[] { "_data" };
	private static final String ADDRESS_SEP = "[\\s,\",',<,>,\\[,\\],(,),{,},:,;,&,?,/,|]";

	// private static final String TAG = "Utils";

	/**
	 *
	 */
	private Utils() {
	}

	public static String[] toStringArray(String emails) {
		String[] tos = emails.split(",");
		for (int i = 0; i < tos.length; i++) {
			tos[i] = tos[i].trim(); // remove extra spaces if any
		}
		return tos;
	}

	public static String getDataPath(Context context, Uri uri) {
		Cursor c = null;
		try {
			c = context.getContentResolver().query(uri, DATA_PATH_PROJECTION,
					null, null, null);
			if (c != null && c.moveToFirst()) {
				return c.getString(0);
			} else {
				return null;
			}
		} finally {
			if (c != null)
				c.close();
		}
	}

	public static CharSequence readResource(Context context, int id) {
		BufferedReader in = null;
		try {
			in = new BufferedReader(new InputStreamReader(context
					.getResources().openRawResource(id)), Constants.BUF_SIZE);
			String line;
			StringBuilder buffer = new StringBuilder();
			while ((line = in.readLine()) != null)
				buffer.append(line).append('\n');
			return buffer;
		} catch (IOException e) {
			return "";
		} finally {
			closeStream(in);
		}
	}

	private static void closeStream(Closeable s) {
		if (s != null) {
			try {
				s.close();
			} catch (IOException e) {
			}
		}
	}

	public static String getVersion(Context context) {
		try {
			return context.getString(R.string.app_version);
			// PackageManager pm = context.getPackageManager();
			// PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
			// return pi.versionName;
		} catch (Exception e) {
		}
		return "?.?"; // unknown
	}

	public static String makeDefaultListName(String emails, List<String> names) {
		String sa[] = emails.split("@", 2);
		String n = sa[0] + " et al";
		n = ensureListName(n);
		return uniqueListName(n, names);
	}

	private static String uniqueListName(String name, List<String> list) {
		ArrayList<String> dups = null;
		for (String s : list) {
			if (s.startsWith(name)) {
				if (dups == null) {
					dups = new ArrayList<String>();
				}
				dups.add(s);
			}
		}
		if (dups == null) {
			return name;
		}
		// append digit at end of name, increment if dup found
		int l = name.length();
		char c = name.charAt(l - 1);
		int d = Character.digit(c, 10);
		d = (d == -1 ? 1 : d++);
		String n = name + " " + d;
		while (dups.contains(n)) {
			n = name + " " + (++d);
		}
		return n;
	}

	public static String ensureListName(String name) {
		// normalize name assuming not null
		name = name.trim();
		name = name.startsWith("@") ? name : "@" + name;
		return name;
	}

	/**
	 * A very crude method to get email addresses
	 * 
	 * @param text
	 * @return
	 */
	public static String[] parseEmail(String text) {
		final String[] sa = text.split(ADDRESS_SEP);
		final HashSet<String> emails = new HashSet<String>();
		for (String s : sa) {
			if (isValidEmail(s)) {
				try {
					InternetAddress[] a = InternetAddress.parse(s);
					String na = a[0].getAddress();
					emails.add(na);
				} catch (Exception e) {
					// e.printStackTrace();
				}
			}
		}
		return (emails.size() == 0 ? null : emails.toArray(new String[0]));
	}

	private static String[] parseEmail(String text, String[] refs) {
		final String[] sa = text.split(ADDRESS_SEP);
		final HashSet<String> emails = new HashSet<String>();
		//
		for (String s : sa) {
			if (isValidEmail(s)) {
				try {
					InternetAddress[] a = InternetAddress.parse(s);
					String v = a[0].getAddress();
					int idx = search(refs, v);
					if (idx < 0) { // not found
						emails.add(v);
					}
				} catch (Exception e) {
					// e.printStackTrace();
				}
			}
		}
		return (emails.size() == 0 ? null : emails.toArray(new String[0]));
	}

	private static int search(String[] refs, String v) {
		// not (refs == nul || refs.length == 0)
		int len = refs.length;
		for (int i = 0; i < len; i++) {
			if (v.equalsIgnoreCase(refs[i])) {
				return i;
			}
		}
		return -1;
	}

	public static boolean isValidEmail(String s) {
		if (TextUtils.isEmpty(s)) {
			return false;
		}
		int idx1 = s.indexOf('@');
		if (idx1 <= 0) {
			return false;
		}
		int idx2 = s.lastIndexOf(".");
		if (idx2 == -1 || idx1 > idx2) {
			return false;
		}
		int len = s.length();
		// domain at least 2 or more chars
		if (idx2 + 2 > len) {
			return false;
		}
		//
		return true;
	}

	public static String toString(String[] emails) {
		if (emails == null || emails.length == 0) {
			return "";
		}
		StringBuilder sb = new StringBuilder(emails[0]);
		for (int i = 1; i < emails.length; i++) {
			sb.append(Email.EMAIL_SEPARATOR);
			sb.append(emails[i]);
		}
		return sb.toString();
	}

	public static String toString(ArrayList<EmailAddress> emails) {
		if (emails == null) {
			return null;
		}
		Iterator<EmailAddress> i = emails.iterator();
		if (!i.hasNext()) {
			return null;
		}
		EmailAddress a = i.next();
		StringBuilder sb = new StringBuilder(a.address);
		while (i.hasNext()) {
			a = i.next();
			sb.append(", ");
			sb.append(a.address);
		}
		return sb.toString();
	}

	public static String[] toStringArray(ArrayList<EmailAddress> list) {
		int size = list.size();
		String[] emails = new String[size];
		int i = 0;
		Iterator<EmailAddress> it = list.iterator();
		while (it.hasNext()) {
			emails[i++] = it.next().address;
		}
		return emails;
	}

	/**
	 * Fast and cheap check for email addresses on clipboard
	 * 
	 * @param context
	 * @return
	 */
	public static boolean noEmailOnClipboard(Context context) {
		ClipboardManager cb = (ClipboardManager) context
				.getSystemService(Context.CLIPBOARD_SERVICE);
		boolean has = cb.hasText();
		if (!has) {
			return true;
		}
		return (cb.getText().toString().indexOf("@") == -1);
	}

	public static void copyToClipboard(Context context, String text) {
		ClipboardManager cb = (ClipboardManager) context
				.getSystemService(Context.CLIPBOARD_SERVICE);
		cb.setText(text);
	}

	public static void copyToClipboard(Context context, EmailContact ec) {
		ClipboardManager cb = (ClipboardManager) context
				.getSystemService(Context.CLIPBOARD_SERVICE);
		cb.setText(toString(ec.emails));
	}

	public static String[] getEmailFromClipboard(Context context) {
		ClipboardManager cb = (ClipboardManager) context
		.getSystemService(Context.CLIPBOARD_SERVICE);
		boolean has = cb.hasText();
		if (!has) {
			return null;
		}
		String txt = cb.getText().toString();
		return parseEmail(txt);
	}

	public static int pasteFromClipboard(Context context, EmailContact ec) {
		ClipboardManager cb = (ClipboardManager) context
				.getSystemService(Context.CLIPBOARD_SERVICE);
		boolean has = cb.hasText();
		if (!has) {
			return 0;
		}
		String txt = cb.getText().toString();
		String[] oa = ec.emails;
		int ol = (oa == null ? 0 : oa.length);
		String[] na = (ol == 0 ? parseEmail(txt) : parseEmail(txt, oa));
		if (na == null) {
			return 0; // none to add
		}
		// >0
		ContactUtils.addEmail(context, ec.id, na);
		// refresh item - no querying DB
		int nl = na.length;
		if (ol > 0) {
			String[] a = new String[ol + nl];
			System.arraycopy(oa, 0, a, 0, ol);
			System.arraycopy(na, 0, a, ol, nl);
			ec.emails = a;
		} else {
			ec.emails = na;
		}
		Arrays.sort(ec.emails); //
		return nl;
	}

	public static String truncate(String s, int max) {
		if (s == null) {
			return null;
		}
		int len = s.length();
		if (len > max) {
			return s.substring(0, max);
		}
		return s;
	}

	public static String ellipsize(String emails, int max) {
		int len = emails.length();
		return (len <= max ? emails : emails.substring(0, max) + "\u2026");
	}

	/**
	 * 1. replace lf/cr with space
	 * 2. trim leading/trailing spaces
	 * @param s
	 * @return
	 */
	public static String normalize(String s) {
		if (s == null) {
			return "";
		}
		final String regex = "[\\s]+";
		return s.replaceAll(regex, " ").trim();
	}
	
	public static boolean isActivityAvailable(Context context, String action) {
		final PackageManager packageManager = context.getPackageManager();
		final Intent i = new Intent(action);
		List<ResolveInfo> act = packageManager.queryIntentActivities(i,
				PackageManager.MATCH_DEFAULT_ONLY);
		return (act != null && act.size() > 0);
	}
	
	public static boolean canSpeak(Context ctx) {
		PackageManager pm = ctx.getPackageManager();
		List<ResolveInfo> act = pm.queryIntentActivities(new Intent(
				RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
		boolean b = (act != null && act.size() > 0);
		return b;
	}
}
